package com.whfc.hdc.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.JSONUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.common.util.VersionUtil;
import com.whfc.hdc.dao.AppDeviceMapper;
import com.whfc.hdc.dao.AppDeviceUpgradeMapper;
import com.whfc.hdc.dao.AppDeviceUpgradePackageMapper;
import com.whfc.hdc.dto.AppDeviceDTO;
import com.whfc.hdc.dto.AppDeviceUpgradeDTO;
import com.whfc.hdc.dto.AppDeviceUpgradePackageDTO;
import com.whfc.hdc.dto.DeviceUpgradeDTO;
import com.whfc.hdc.entity.AppDeviceUpgrade;
import com.whfc.hdc.entity.AppDeviceUpgradePackage;
import com.whfc.hdc.enums.DeviceUpgradeState;
import com.whfc.hdc.redis.DeviceUpgradeRedisDao;
import com.whfc.hdc.service.AppDeviceOtaService;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/8/23 15:09
 */
@DubboService(interfaceClass = AppDeviceOtaService.class, version = "1.0.0")
public class AppDeviceOtaServiceImpl implements AppDeviceOtaService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public static final Integer MASTER = 0x01;

    public static final Integer SLAVE = 0x00;

    public static AppDeviceUpgradeDTO NO_UPGRADE = new AppDeviceUpgradeDTO(0);

    @Autowired
    private AppDeviceMapper deviceMapper;

    @Autowired
    private AppDeviceUpgradeMapper upgradeMapper;

    @Autowired
    private AppDeviceUpgradePackageMapper upgradePackageMapper;

    @Autowired
    private DeviceUpgradeRedisDao deviceUpgradeRedisDao;

    @Override
    public PageData<AppDeviceUpgradePackageDTO> upgradePackageList(Integer deviceType, Integer pageNum, Integer pageSize) throws BizException {
        logger.info("查询升级包列表,deviceType:{},pageNum:{},pageSize:{}", deviceType, pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AppDeviceUpgradePackageDTO> list = upgradePackageMapper.selectPackageList(deviceType);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public void addUpgradePackage(AppDeviceUpgradePackageDTO dto) throws BizException {
        logger.info("添加升级包,dto:{}", JSONUtil.toString(dto));
        Integer deviceType = dto.getDeviceType();
        String masterVer = dto.getMasterVer();
        String slaveVer = dto.getSlaveVer();
        if (!StringUtils.isEmpty(masterVer)) {
            int cnt = upgradePackageMapper.countByDeviceTypeAndMasterVer(deviceType, masterVer);
            if (cnt > 0) {
                throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "已存在相同版本号升级包");
            }
            AppDeviceUpgradePackage record = new AppDeviceUpgradePackage();
            record.setDeviceType(deviceType);
            record.setMasterVer(masterVer);
            record.setFileName(dto.getFileName());
            upgradePackageMapper.insertSelective(record);
        } else if (!StringUtils.isEmpty(slaveVer)) {
            int cnt = upgradePackageMapper.countByDeviceTypeAndSlaveVer(deviceType, slaveVer);
            if (cnt > 0) {
                throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "已存在相同版本号升级包");
            }
            AppDeviceUpgradePackage record = new AppDeviceUpgradePackage();
            record.setDeviceType(deviceType);
            record.setSlaveVer(slaveVer);
            record.setFileName(dto.getFileName());
            upgradePackageMapper.insertSelective(record);
        }
    }

    @Override
    public void delUpgradePackage(Integer packageId) throws BizException {
        logger.info("删除升级包,packageId:{}", packageId);
        List<AppDeviceUpgradeDTO> upgradeDTOList = upgradeMapper.selectUnCompletedByPackageId(packageId);
        if (upgradeDTOList.size() > 0) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "升级包对应有未完成的硬件升级");
        }
        upgradePackageMapper.logicDeleteById(packageId);
    }

    @Override
    public PageData<AppDeviceUpgradeDTO> upgradeDeviceList(Integer pageNum, Integer pageSize, Integer packageId, Integer state, String keyword) throws BizException {
        logger.info("查询硬件升级列表,pageNum:{},pageSize:{},packageId:{},state:{},keyword:{}", pageNum, pageSize, packageId, state, keyword);
        AppDeviceUpgradePackage upgradePackage = upgradePackageMapper.selectByPrimaryKey(packageId);
        if (upgradePackage == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "升级包不存在");
        }
        PageHelper.startPage(pageNum, pageSize);
        List<AppDeviceUpgradeDTO> list = upgradeMapper.selectByPackageIdAndState(packageId, state);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public List<AppDeviceUpgradeDTO> upgradeDeviceList(Integer packageId) {
        List<AppDeviceUpgradeDTO> list = upgradeMapper.selectByPackageId(packageId);
        return list;
    }

    @Override
    public void addUpgradeDevice(Integer packageId, List<Integer> deviceIdList) throws BizException {
        logger.info("添加硬件升级,packageId:{},deviceIdList:{}", packageId, deviceIdList);
        //验证deviceId
        if (deviceIdList != null && deviceIdList.size() == 0) {
            return;
        }
        AppDeviceUpgradePackage upgradePackage = upgradePackageMapper.selectByPrimaryKey(packageId);
        if (upgradePackage != null) {

            //去除已添加的硬件ID
            List<AppDeviceUpgradeDTO> upgradeDTOList = upgradeMapper.selectByPackageId(packageId);
            List<Integer> existIdList = upgradeDTOList.stream().map(dto -> dto.getDeviceId()).collect(Collectors.toList());
            deviceIdList.removeAll(existIdList);

            //验证剩余的deviceId
            if (deviceIdList.size() > 0) {
                Integer deviceType = upgradePackage.getDeviceType();
                List<AppDeviceDTO> deviceDTOList = deviceMapper.selectByTypeAndIds(deviceType, deviceIdList);
                if (deviceDTOList.size() != deviceIdList.size()) {
                    throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "硬件升级参数错误");
                }

                List<AppDeviceUpgrade> upgradeList = new ArrayList<>(deviceIdList.size());
                for (AppDeviceDTO deviceDTO : deviceDTOList) {
                    AppDeviceUpgrade upgrade = new AppDeviceUpgrade();
                    upgrade.setPackageId(packageId);
                    upgrade.setDeviceType(deviceType);
                    upgrade.setDeviceId(deviceDTO.getId());
                    upgrade.setDeviceSn(deviceDTO.getSn());
                    upgrade.setMasterVer(upgradePackage.getMasterVer());
                    upgrade.setSlaveVer(upgradePackage.getSlaveVer());
                    upgradeList.add(upgrade);
                }

                //批量插入新规则
                upgradeMapper.batchInsert(upgradeList);

                //删除缓存
                deviceUpgradeRedisDao.del(deviceIdList);
            }
        }
    }

    @Override
    public void delUpgradeDevice(Integer upgradeId) throws BizException {
        logger.info("删除硬件升级,upgradeId:{}", upgradeId);
        AppDeviceUpgrade upgrade = upgradeMapper.selectByPrimaryKey(upgradeId);
        if (upgrade != null) {
            //删除数据
            upgradeMapper.logicDeleteById(upgradeId);

            //删除缓存
            deviceUpgradeRedisDao.del(upgrade.getDeviceId());
        }
    }

    @Override
    public void updateUpgradeProgress(Integer deviceId, Integer masterOrSlave, String newVer, Integer finish, Integer total) throws BizException {
        logger.info("更新硬件升级进度,deviceId:{},masterOrSlave:{},newVer:{},finish:{},total:{}", deviceId, masterOrSlave, newVer, finish, total);

        AppDeviceUpgrade upgrade = upgradeMapper.selectByDeviceId(deviceId);
        if (upgrade != null) {
            boolean isMaster = MASTER.equals(masterOrSlave) && upgrade.getMasterVer().equalsIgnoreCase(newVer);
            boolean isSlave = SLAVE.equals(masterOrSlave) && upgrade.getSlaveVer().equalsIgnoreCase(newVer);
            if (isMaster || isSlave) {
                if (finish == 0) {
                    upgrade.setFinish(finish);
                    upgrade.setTotal(total);
                    upgrade.setState(DeviceUpgradeState.INIT.getValue());
                    upgrade.setStartTime(new Date());
                    upgradeMapper.updateByPrimaryKeySelective(upgrade);
                }
                if (finish > 0 && finish < total) {
                    upgrade.setFinish(finish);
                    upgrade.setTotal(total);
                    upgrade.setState(DeviceUpgradeState.UNCOMPLETE.getValue());
                    upgradeMapper.updateByPrimaryKeySelective(upgrade);
                } else if (finish.equals(total)) {
                    upgrade.setFinish(finish);
                    upgrade.setTotal(total);
                    upgrade.setState(DeviceUpgradeState.COMPLETE.getValue());
                    upgrade.setEndTime(new Date());
                    upgradeMapper.updateByPrimaryKeySelective(upgrade);
                    //删除缓存
                    deviceUpgradeRedisDao.del(deviceId);
                }
            }
        }
    }

    @Override
    public void upgradeComplete(Integer deviceId) throws BizException {
        logger.info("硬件升级完毕,deviceId:{}", deviceId);
        upgradeMapper.logicDeleteByDeviceId(deviceId);
        //删除缓存
        deviceUpgradeRedisDao.del(deviceId);
    }

    @Override
    public DeviceUpgradeDTO getDeviceUpgrade(Integer deviceType, Integer deviceId, String masterVer, String slaveVer) throws BizException {
        logger.info("查询硬件升级配置,deviceType:{},deviceId:{},masterVer:{},slaveVer:{}", deviceType, deviceId, masterVer, slaveVer);
        AppDeviceUpgradeDTO upgrade = deviceUpgradeRedisDao.get(deviceId);
        //缓存未命中
        if (upgrade == null) {
            upgrade = upgradeMapper.selectUpgradeByDeviceId(deviceId);
            //缓存配置
            if (upgrade != null) {
                deviceUpgradeRedisDao.set(deviceId, upgrade);
            }
            //缓存空数据,避免查数据库
            else {
                deviceUpgradeRedisDao.set(deviceId, NO_UPGRADE);
            }
        }
        //缓存命中
        else {
            logger.info("查询硬件升级配置,缓存命中,{}", JSONUtil.toString(upgrade));
        }
        DeviceUpgradeDTO upgradeDTO = null;
        if (upgrade != null) {
            //先检查主机版本号
            if (!StringUtils.isEmpty(upgrade.getMasterVer())) {
                String oldVer = masterVer;
                String newVer = upgrade.getMasterVer();
                int result = VersionUtil.compareVersion(oldVer, newVer);
                upgradeDTO = new DeviceUpgradeDTO();
                upgradeDTO.setOldVer(masterVer);
                upgradeDTO.setNewVer(upgrade.getMasterVer());
                upgradeDTO.setMasterOrSlave(MASTER);
                upgradeDTO.setNeedUpgrade(result < 0);
            }
            //后检查从机版本号
            else if (!StringUtils.isEmpty(upgrade.getSlaveVer())) {
                String oldVer = slaveVer;
                String newVer = upgrade.getSlaveVer();
                int result = VersionUtil.compareVersion(oldVer, newVer);
                upgradeDTO = new DeviceUpgradeDTO();
                upgradeDTO.setOldVer(masterVer);
                upgradeDTO.setNewVer(upgrade.getSlaveVer());
                upgradeDTO.setMasterOrSlave(SLAVE);
                upgradeDTO.setNeedUpgrade(result < 0);
            }
        }

        if (ObjectUtils.isEmpty(upgradeDTO)) {
            upgradeDTO = new DeviceUpgradeDTO();
            upgradeDTO.setNeedUpgrade(false);
        }

        return upgradeDTO;
    }

    @Override
    public void reloadUpgradeCache() throws BizException {
        deviceUpgradeRedisDao.delAll();
    }
}
